package fitness;

import java.io.Serializable;
import java.util.Random;

import optimizers.commons.GAConstants;
import optimizers.ganeat.oscillator.faststrong.ConstantsFSO;
import optimizers.ganeat.sin.ConstantsSin;
import util.MyUtil;
import model.Input;
import model.OligoSystemGeneral;

public class FastStrongOscillatorFitness extends Fitness implements
		Serializable {

	public double goal(int i, int firstPeak) {
		return (1 + Math.sin((i - firstPeak) * 2 * Math.PI
				/ ConstantsSin.period + Math.PI / 2))
				* ConstantsSin.height / 2;
	}

	@Override
	public FitnessResult evaluateFitness(OligoSystemGeneral oligoModel) {
		FastStrongOscillatorResult result = new FastStrongOscillatorResult();
		result.amplitute = 0;
		result.limitcycle = .1;
		result.speed = ConstantsFSO.calculationTime;
		try {
			int time = 1;
			int peakTime = 0;
			int bottomTime = 0;
			int output = oligoModel.nameToInt.get("a");
			double[][] data = oligoModel.getTimeSeriesComplexModel();
			boolean firstIn = true;
			boolean secondIn = true;
			double firstPeakIn = 0;
			double firstPeakInTime = 0;
			while (peakTime != -1
					&& time < ConstantsFSO.skipTime
							+ ConstantsFSO.calculationTime) {
				peakTime = MyUtil.getFirstPeak(data[output], time);
				time = peakTime;
				if (peakTime == -1) {
					return result;
				}
				bottomTime = MyUtil.getFirstBottom(data[output], time);
				time = bottomTime;
				if (bottomTime == -1) {
					return result;
				}
				double amplitute = data[output][peakTime]
						- data[output][bottomTime];
				if (peakTime != -1
						&& (peakTime < ConstantsFSO.skipTime || peakTime > ConstantsFSO.skipTime
								+ ConstantsFSO.calculationTime)) {
					result.amplitute += 0.1;
				} else if (peakTime > ConstantsFSO.skipTime
						&& peakTime < ConstantsFSO.skipTime
								+ ConstantsFSO.calculationTime) {
					if (!firstIn && secondIn) {
						secondIn = false;
						result.speed = peakTime - firstPeakInTime;
						if (result.speed < 10) {
							System.out.println("weird");
							MyUtil.getFirstPeak(data[output],
									ConstantsFSO.skipTime);
						}
					}
					if (firstIn) {
						firstIn = false;
						firstPeakIn = data[output][peakTime];
						firstPeakInTime = peakTime;
						result.amplitute += amplitute + 0.1;
					}
				}
			}
			int lastPeakTime = MyUtil.getLastPeak(data[output],
					data[output].length - 1);

			if (firstPeakIn != 0 && lastPeakTime != 0) {
				result.limitcycle = 1 / (1 + Math.abs(firstPeakIn
						- data[output][lastPeakTime])
						/ data[output][lastPeakTime]);
			}

		} catch (Exception ex) {
			// ex.printStackTrace();
		}
		return result;
	}

	@Override
	public FitnessResult evaluateFitnessSimple(OligoSystemGeneral indiv) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public FitnessResult minFitness(OligoSystemGeneral indiv) {
		FastStrongOscillatorResult result = new FastStrongOscillatorResult();
		result.amplitute = 0;
		result.limitcycle = .1;
		result.speed = ConstantsFSO.calculationTime;
		return result;
	}
}
